import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Like, Repository } from 'typeorm';
import { RoleAdminAllDto, RoleAdminCreateDto, RoleAdminUpdateDto, } from './role.dto';
import { RoleModel } from './role.model';
import { BizFailedException } from "@/common/biz-failed/biz-failed.exception";
import { BizFailedCodeEnum } from "@/common/biz-failed/biz-failed.enum";
import { omitUndefined } from "@/common/utils/utils";
import { AdminuserRoleModel } from "@/module/adminuser-role/adminuser-role.model";
import { Transactional } from "typeorm-transactional";
import { RoleResourceModel } from "@/module/role-resource/role-resource.model";

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(RoleModel)
    private readonly roleModelRepository: Repository<RoleModel>,
    @InjectRepository(RoleResourceModel)
    private readonly roleResourceModelRepository: Repository<RoleResourceModel>,
    @InjectRepository(AdminuserRoleModel)
    private readonly adminuserRoleModelRepository: Repository<AdminuserRoleModel>,
  ) {}

  async adminAll() {
    const res = await this.roleModelRepository.createQueryBuilder('role')
      .leftJoinAndSelect('role.roleResources', 'roleResources')
      .select([
        'role.id',
        'role.uuid',
        'role.name',
        'role.desc',
        'role.createTime',
        'role.updateTime',
        'roleResources.uuid',
        'roleResources.resourceUuid',
      ])
      .orderBy({
        'role.id': 'DESC',
      })
      .getMany();
    return res.map(item=>{
      const {roleResources, ...restItem} = item;
      return {
        ...restItem,
        resourceUuids: roleResources.map(item=>item.resourceUuid),
      }
    })
  }

  @Transactional()
  async adminCreate(body: RoleAdminCreateDto): Promise<void> {
    const {resourceUuids, ...restBody} = body;
    try {
      const role = await this.roleModelRepository.save({
        ...restBody,
      });
      if(resourceUuids){
        await this.roleResourceModelRepository.save(resourceUuids.map(item=>{
          return {
            roleUuid: role.uuid,
            resourceUuid: item,
          }
        }))
      }
    } catch (e) {
      if (e.constraint === 'ROLE.name') {
        throw new BizFailedException(BizFailedCodeEnum.ROLE_EXISTS);
      }
      throw e;
    }
  }

  @Transactional()
  async adminUpdate(body: RoleAdminUpdateDto, uuid: string): Promise<void> {
    const {resourceUuids, ...restBody} = body;
    try {
      await this.roleModelRepository.update(
        {
          uuid,
        },
        omitUndefined(restBody),
      );
      if(resourceUuids){
        await this.roleResourceModelRepository.delete({
          roleUuid: uuid,
        })
        await this.roleResourceModelRepository.save(resourceUuids.map(item=>{
          return {
            roleUuid: uuid,
            resourceUuid: item,
          }
        }))
      }
    } catch (e) {
      if (e.constraint === 'ROLE.name') {
        throw new BizFailedException(BizFailedCodeEnum.ROLE_EXISTS);
      }
      throw e;
    }
  }

  @Transactional()
  async adminDestroy(uuid: string): Promise<void> {
    const count = await this.adminuserRoleModelRepository.count({
      where: {
        roleUuid: uuid,
      },
    });
    if (count) {
      throw new BizFailedException(BizFailedCodeEnum.ROLE_USED);
    }
    await Promise.all([
      this.roleModelRepository.delete({
        uuid,
      }),
      this.roleResourceModelRepository.delete({
        roleUuid: uuid,
      }),
    ])
  }

}
